package com.evildog.workspace.invest.application.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evildog.workspace.common.exception.BadRequestException;
import com.evildog.workspace.dependencies.mybatis.object.QueryConditionDTO;
import com.evildog.workspace.invest.application.bo.BillBO;
import com.evildog.workspace.invest.application.bo.BillListBO;
import com.evildog.workspace.invest.application.bo.BillReportStatBO;
import com.evildog.workspace.invest.application.convert.BillConvert;
import com.evildog.workspace.invest.application.dto.BillDTO;
import com.evildog.workspace.invest.application.dto.BillListDTO;
import com.evildog.workspace.invest.application.entity.Bill;
import com.evildog.workspace.invest.application.entity.BillListDO;
import com.evildog.workspace.invest.application.enums.BillTypeEnum;
import com.evildog.workspace.invest.application.enums.InvestCustomExceptionDesc;
import com.evildog.workspace.invest.application.mapper.BillMapper;
import com.evildog.workspace.invest.application.service.BillService;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class BillServiceImpl extends ServiceImpl<BillMapper, Bill> implements BillService {

    @Override
    public List<BillListBO> getList(List<QueryConditionDTO> queryCondition, BillListDTO dto) {
        List<BillListDO> billList = this.baseMapper.getList(queryCondition, dto);


        // key localDate value List<PhotoListDO>
        ImmutableListMultimap<LocalDate, BillListDO> mapBill = Multimaps.index(billList,
                bill -> Objects.requireNonNull(bill).getCreateTime().toLocalDate());


        List<BillListBO> result = new ArrayList<>();

        mapBill.asMap().forEach((localDate, list) -> result.add(
                new BillListBO()
                        .setDate(localDate)
                        .setBills(BillConvert.INSTANCE.convert(list))));


        return result;
    }

    @Override
    public BillBO getDetailById(Long id) {
        Bill bill = getById(id);
        Assert.notNull(bill, "bill is null!");
        return BillConvert.INSTANCE.convert(bill);
    }

    @Override
    public boolean save(BillDTO dto) {
        Bill newBill = BillConvert.INSTANCE.convert(dto);
        return save(newBill);
    }

    @Override
    public BillReportStatBO getTotalReport(int year, int month) {

        LocalDate startDate = LocalDate.of(year, month, 1);
        LocalDate endDate = startDate.plusMonths(1).minusDays(1);

        List<Bill> bills = list(Wrappers.<Bill>lambdaQuery()
                .select(Bill::getWorth, Bill::getType)
                .ge(Bill::getDate, startDate)
                .le(Bill::getDate, endDate)
        );

        BillReportStatBO reportStatBO = new BillReportStatBO();
        bills.forEach(bill -> {
            if (Objects.equals(BillTypeEnum.EXPEND.getType(), bill.getType())) {
                reportStatBO.setExpend(reportStatBO.getExpend() + bill.getWorth());
            } else if (Objects.equals(BillTypeEnum.INCOME.getType(), bill.getType())) {
                reportStatBO.setIncome(reportStatBO.getIncome() + bill.getWorth());
            } else {
                throw new BadRequestException(InvestCustomExceptionDesc.BAD_BILL_TYPE);
            }
        });

        return reportStatBO;
    }

    @Override
    public boolean updateById(Long id, BillDTO dto) {
        Bill oldBill = getById(id);
        Assert.notNull(oldBill, "bill is null!");
        Bill newBill = BillConvert.INSTANCE.convert(dto);
        newBill.setId(id);
        return updateById(newBill);
    }
}
